﻿using System;
using System.Collections.Generic;
using System.Reflection;
using UnityEngine;
using UnityEngine.U2D;
using Object = UnityEngine.Object;

namespace Framework
{
    public class ModuleBase<TController,TModel,TView> : IModule, IEventListener, ILoader where TController:IController<TView>, new() where TModel:IModel, new() where TView:View
    {
        public static float OffSetX = 0;
        public static float OffSetY = 0;

        protected TController Controller;
        protected TModel Model;
        protected TView FirstView;

        protected List<IController<TView>> _controllers;

        public string moduleName { get; private set; }

        public ILoader ResLoader { get; private set; }
        

        private readonly Transform moduleParent;

        private RectTransform root;
        private Transform root3D;

        private Dictionary<Type, IService> _services;
        private Dictionary<Type,IModel> _models;
        
        
        private IEventDispatcher _eventDispatcher;
        private IModuleEventDispatcher _moduleEventDispatcher;

        /// <summary>
        /// 模块名称，UI根节点Canvas设置
        /// </summary>
        /// <param name="moduleName">模块名称</param>
        /// <param name="moduleParent">UI根节点Canvas</param>
        /// <param name="moduleEvent">模块事件</param>
        public ModuleBase(string moduleName, Transform moduleParent, IModuleEventDispatcher moduleEventDispatcher)
        {
            this.moduleParent = moduleParent;
            this.moduleName = moduleName;
            this._moduleEventDispatcher = moduleEventDispatcher;

            Init();
        }

        private void Init()
        {
            _controllers = new List<IController<TView>>();
            _services = new Dictionary<Type, IService>();
            _models = new Dictionary<Type, IModel>();
            
            _eventDispatcher = new EventDispatcher();
            ResLoader = new ResLoader();

            CreateModuleContainer();
            FirstView = AddFirstView();
            OnRegister();
        }

        private void CreateModuleContainer()
        {
            GameObject container = new GameObject(moduleName);
            var rect = container.AddComponent<RectTransform>();
            rect.anchorMin = new Vector2(0, 0);
            rect.anchorMax = new Vector2(1, 1);
            rect.offsetMin = Vector2.zero;
            rect.offsetMax = new Vector2(OffSetX, OffSetY);
            container.transform.SetParent(moduleParent, false);

            root = rect;
        }

        private TView AddFirstView()
        {
            GameObject go = ResLoader.LoadGameObject("Bundles/Module/" + moduleName + "/" + moduleName + "View.prefab", true);
            // go.transform.SetParent(root, false);
           
            Assembly assembly = Assembly.GetExecutingAssembly();
            Type cls = assembly.GetType(moduleName + "View");
            View view = (View)go.AddScriptComponent(cls);
            AddView(view);

            return (TView) view;
        }
        
        /// <summary>
        /// 注册第一个Controller，Model
        /// </summary>
        protected virtual void OnRegister()
        {
            Controller = new TController();
            RegisterController(Controller, FirstView);

            Model = new TModel();
            RegisterModel(Model);
        }

        public void RegisterController<TV>(IController<TV> controller, TV view) where TV : View
        {
            controller.Connect(view,_eventDispatcher, _moduleEventDispatcher, _services, _models);
            _controllers.Add((IController<TView>) controller);
        }

        public void UnRegisterController<TV>(IController<TV> controller) where TV : View
        {
            controller.Dispose();
            _controllers.Remove((IController<View>)controller);
        }

        public void RegisterModel(IModel model)
        {
            model.Connect(_eventDispatcher, _moduleEventDispatcher);
            model.Init();
            var type = model.GetType();
            if (_models.ContainsKey(type))
            {
                Log.Error("重复注册Model："+type.Name);
            }
            else
            {
                _models.Add(type, model);
            }
        }

        public void UnRegisterModel(IModel model)
        {
            var type = model.GetType();
            _models.Add(type, model);
            model.Dispose();
        }

        public void RegisterService<TService>() where TService:IService
        {
            var type = typeof(TService);
            if (_services.TryGetValue(type, out IService service))
            {
                Log.Error("重复注册Service："+type.Name);
            }
            else
            {
                service = (IService) Activator.CreateInstance(type);
                service.Connect(_eventDispatcher, _models);
                _services.Add(type, service);
                
            }
        }

        public void UnRegisterService<TService>() where TService:IService
        {
            var type = typeof(TService);
            if (_services.ContainsKey(type))
            {
                _services[type].Dispose();
                _services.Remove(type);
            }
            else
            {
                Log.Error(type.Name + " Service没有注册！");
            }
        }


        public void AddView(View view)
        {
            view.transform.SetParent(root, false);

            view.PreInit(this, _eventDispatcher, ResLoader, _moduleEventDispatcher);
        }
        
        public void ConnectView3D(View3D view)
        {
            view.transform.SetParent(root3D);
            view.PreInit(this, _eventDispatcher, ResLoader, _moduleEventDispatcher);
        }

        /// <summary>
        /// 子View关联Module功能
        /// </summary>
        /// <param name="view"></param>
        public void ConnectView(View view)
        {
            view.PreInit(this, _eventDispatcher, ResLoader, _moduleEventDispatcher);
        }
        
        public void OnShow(params object[] data)
        {
            
        }

        public void OnHide()
        {
            
        }
        
        public void Show()
        {
            root.gameObject.SetActive(true);
        }
        public void Hide()
        {
            root.gameObject.SetActive(false);
        }

        public void Destroy()
        {
#if UNITY_EDITOR
            Object.DestroyImmediate(root.gameObject);
#else
            Object.Destroy(root.gameObject);
#endif
            
            ResLoader.UnloadAllAsset();
            
            _eventDispatcher.Cleanup();
            
            //TODO: 移除模块事件
            // _moduleEventDispatcher.Dispose();

            _eventDispatcher = null;
            _moduleEventDispatcher = null;
            
            foreach (var controller in _controllers)
            {
                controller.Dispose();
            }

            foreach (KeyValuePair<Type,IModel> model in _models)
            {
                model.Value.Dispose();
            }

            foreach (KeyValuePair<Type,IService> service in _services)
            {
                service.Value.Dispose();
            }
            
            _controllers.Clear();
            _models.Clear();
            _services.Clear();

            _controllers = null;
            _models = null;
            _services = null;
        }
        
        public void SetTopView()
        {
            root.SetAsLastSibling();
        }

        #region 接口委托
        public GameObject LoadGameObject(string path, bool instantiate = false)
        {
            return ResLoader.LoadGameObject(path, instantiate);
        }

        public void LoadGameObjectAsync(string path, Action<GameObject> onComplete, bool instantiate)
        {
            ResLoader.LoadGameObjectAsync(path, onComplete, instantiate);
        }

        public Sprite LoadSprite(string path)
        {
            return ResLoader.LoadSprite(path);
        }

        public Texture LoadTexture(string path)
        {
            return ResLoader.LoadTexture(path);
        }

        public void LoadSpriteAtlas(string path, Action<SpriteAtlas> onComplete)
        {
            ResLoader.LoadSpriteAtlas(path, onComplete);
        }

        public Sprite GetAtlasSprite(string assetName)
        {
            return ResLoader.GetAtlasSprite(assetName);
        }

        public void UnloadAsset(string path, bool unloadDependencies = false)
        {
            ResLoader.UnloadAsset(path, unloadDependencies);
        }

        public void UnloadAllAsset()
        {
            ResLoader.UnloadAllAsset();
        }

        public string LoadText(string path)
        {
            return ResLoader.LoadText(path);
        }
        public void AddListener<T1>(string eventName, Action<T1> handler)
        {
            _eventDispatcher.AddListener(eventName, handler);
        }

        public void AddListener(string eventName, Action handler)
        {
            _eventDispatcher.AddListener(eventName, handler);
        }

        public void AddListener<T1, U1>(string eventName, Action<T1, U1> handler)
        {
            _eventDispatcher.AddListener(eventName, handler);
        }

        public void AddListener<T1, U1, V1>(string eventName, Action<T1, U1, V1> handler)
        {
            _eventDispatcher.AddListener(eventName, handler);
        }

        public void AddListener<T1, U1, V1, W>(string eventName, Action<T1, U1, V1, W> handler)
        {
            _eventDispatcher.AddListener(eventName, handler);
        }

        public void Cleanup()
        {
            _eventDispatcher.Cleanup();
        }

        public void RemoveEvents(string eventName)
        {
            _eventDispatcher.RemoveEvents(eventName);
        }

        public void RemoveListener(string eventName, Action handler)
        {
            _eventDispatcher.RemoveListener(eventName, handler);
        }

        public void RemoveListener<T1>(string eventName, Action<T1> handler)
        {
            _eventDispatcher.RemoveListener(eventName, handler);
        }

        public void RemoveListener<T1, U1>(string eventName, Action<T1, U1> handler)
        {
            _eventDispatcher.RemoveListener(eventName, handler);
        }

        public void RemoveListener<T1, U1, V1>(string eventName, Action<T1, U1, V1> handler)
        {
            _eventDispatcher.RemoveListener(eventName, handler);
        }

        public void RemoveListener<T1, U1, V1, W>(string eventName, Action<T1, U1, V1, W> handler)
        {
            _eventDispatcher.RemoveListener(eventName, handler);
        }
        #endregion

       
    }

}